feat(beads): scope fleet snapshot and Bearings reads to firstmate's fleet label - #28
Conversation
Stage 0 of the beads-authority migration (data/beads-authority-migration-scout/report.md
section 4): define fm_beads_fleet_label() in bin/fm-tasks-axi-lib.sh as the single owner
of the firstmate-fleet label ("fleet:firstmate" by default) that every bead firstmate
creates for its own dispatched work should carry, so a `task list --label` call can scope
to firstmate's fleet instead of the shared federated store's full cross-project set.
Stage 1: bin/fm-fleet-snapshot.sh's backlog_json gains a beads-backed branch
(backlog_json_beads) that reads this fleet's open/in_progress/blocked beads, scoped by
that label, into the same fm-fleet-snapshot.v1 records[] shape the existing markdown
parser (renamed to backlog_json_markdown) produces, when config/backlog-backend=beads.
It falls back to the markdown parse on a beads read failure. Beads-sourced records are
always structured:true with requires_child_metadata:false and captain_actionable:false,
so main_inventory_json never flags them as orphaned or unstructured; dependency-graph
fields and state/*.meta correlation are left for a later stage per the report.
bin/fm-bearings-snapshot.sh needs no functional change: it only ever reads the canonical
snapshot's .backlog.records[] and never re-parses data/backlog.md itself, so it inherits
beads-backend awareness for free. Added a header note documenting that.
Default-backend (tasks-axi/manual) output is unchanged: backlog_json_markdown's body is
untouched, and the beads-only fields (source, fleet_label) only ever appear on the beads
path. A regression test asserts the default path carries neither field.
Documented the label convention and snapshot/Bearings beads-awareness in
docs/configuration.md's "Backlog backend" section.
…ull id/title, disclose truncation
…pe, env bounds, unwired fleet label
|
Warning Review limit reached
Next review available in: 5 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (7)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Intent
Beads-authority migration Stage 0 + Stage 1: define and document a firstmate-fleet beads label (fleet:firstmate) so task list calls can scope to firstmate's own fleet, then make bin/fm-fleet-snapshot.sh and bin/fm-bearings-snapshot.sh read this fleet's in-flight/queued state from the beads store (scoped by that label) when config/backlog-backend=beads. Default (tasks-axi/manual) backend output must stay byte-identical. Read-capability only: no home is flipped to beads, no data migrated, no fm-spawn/fm-teardown/decision-hold changes.
What Changed
fleet:firstmatebeads label convention inbin/fm-tasks-axi-lib.shsotask listcalls can be scoped to this fleet's own beads.backlog_json_beadspath tobin/fm-fleet-snapshot.shthat reads in-flight/queued state from the beads store (viatask list --label ... --json) whenconfig/backlog-backend=beads, bounded by a read limit/timeout, with null-safeid/titlehandling and truncation disclosure; default tasks-axi/manual backend output is unchanged.bin/fm-bearings-snapshot.shto surface the beads-backed fleet view alongside the existing backends, and updateddocs/configuration.mdto document the new snapshot shape, environment bounds, and the not-yet-wired fleet label.tests/fm-beads-backend.test.shandtests/fm-fleet-snapshot-view.test.shcoverage for the new beads-scoped snapshot path.Risk Assessment
✅ Low: The change is read-only (no fm-spawn/fm-teardown/data mutation), gated behind config/backlog-backend=beads which no home currently sets, preserves byte-identical default-backend output (covered by a dedicated regression test), and the three warnings/info items from round 1 (timeout, null-title crash, silent truncation) have already been fixed; only a minor, currently-inert schema inconsistency remains.
Testing
All existing and new automated tests pass (fm-beads-backend.test.sh, fm-fleet-snapshot-view.test.sh, fm-bearings-snapshot.test.sh with no regressions), and manual end-to-end CLI runs confirm the beads-scoped fleet:firstmate label correctly drives fm-fleet-snapshot.sh and fm-bearings-snapshot.sh output while the default tasks-axi/manual backend output remains byte-identical to the base commit.
Evidence: Beads-backend fleet snapshot JSON (real fm-fleet-snapshot.sh run against a fake `task` CLI honoring the fleet:firstmate label contract)
Evidence: Bearings snapshot rendered from the same beads-backed home (free-rides the snapshot's beads branch)
Evidence: Default-backend byte-identical comparison: base-commit vs target-commit fm-fleet-snapshot.sh JSON output, diffed after stripping only timestamp/root-path fields
Pipeline
Updates from git push no-mistakes
✅ **intent** - passed
✅ No issues found.
✅ **Rebase** - passed
✅ No issues found.
bin/fm-fleet-snapshot.sh:425- The newtask list --label ... --jsoncall in backlog_json_beads (and the fm_beads_backend_available probe it depends on) runs with no timeout bound, unlike every other external/subprocess read in this file (secondmate summary, registry read, parent activity, terminal check all wrap their command in run_timed with a dedicated FM_SNAPSHOT_*_TIMEOUT). If the beads/taskbackend hangs (federated store unresponsive, lock contention), fm-fleet-snapshot.sh — used at session start and for supervision decisions — can now hang indefinitely instead of failing fast. Wrap the call in run_timed with a new FM_SNAPSHOT_BEADS_TIMEOUT, consistent with the file's established pattern.bin/fm-fleet-snapshot.sh:467-raw:(.id + " - " + .title)concatenates .id/.title with no null guard. If any bead returned bytask list --jsonhas a null id or title (malformed record from the federated store), jq raises a runtime error, backlog_json_beads returns nonzero, and the top-levelBACKLOG_JSON=$(backlog_json) || ... exit 1aborts the entire snapshot with 'backlog read failed' instead of degrading gracefully the way backlog_json_markdown does for every other missing field (it uses// nullthroughout). Guard with(.id // "?")/(.title // "(untitled)")or similar.bin/fm-fleet-snapshot.sh:426- backlog_json_beads caps the beads read at FM_SNAPSHOT_BEADS_LIMIT (200) with no truncation disclosure in the output, whereas every other bounded read in this file (secondmate registry, parent activity, terminal check) surfaces an explicit truncated/records_truncated flag. If a fleet accumulates more than 200 in-flight+queued beads, the snapshot silently drops the overflow with no signal to callers (Bearings, supervisors) that the view is incomplete.🔧 Fix: Bound beads task list read with timeout, guard null id/title, disclose truncation
1 info still open:
bin/fm-fleet-snapshot.sh:463- backlog_json_beads serializes.priority | tostringfor every bead. When a bead has no priority set, jq's.priorityis null andtostringturns it into the literal string "null" rather than JSON null, unlike backlog_json_markdown's metadata() helper which yields real null for an absent field. No current consumer reads records[].priority, so there's no live breakage today, but it's a schema inconsistency between the two backend paths that could surprise a future consumer doingpriority == nullchecks (the pattern already used for hold_reason/blocked_reason/local_note in this same file). Fix:priority:(if .priority == null then null else (.priority | tostring) end).✅ **Test** - passed
✅ No issues found.
bash tests/fm-beads-backend.test.shbash tests/fm-fleet-snapshot-view.test.shbash tests/fm-bearings-snapshot.test.shManual: FM_HOME with config/backlog-backend=beads + faketaskCLI matching the real beads list contract, ran bin/fm-fleet-snapshot.sh --json and bin/fm-bearings-snapshot.sh directlyManual: diffed bin/fm-fleet-snapshot.sh --json output between base commit (4ca2fe9, via git archive) and target commit (a155fb5) against an identical markdown-backlog fixture home to confirm byte-identical default-backend output✅ **Document** - passed
✅ No issues found.
✅ **Lint** - passed
✅ No issues found.
✅ **Push** - passed
✅ No issues found.